package com.galen.manual.security;

import com.galen.manual.context.UserContext;
import com.galen.manual.context.UserContextHolder;
import com.galen.manual.entity.User;
import com.galen.manual.mapper.UserMapper;
import com.galen.manual.utils.JwtUtil;
import com.galen.manual.utils.UserContextUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Slf4j
@Component
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserDetailsService userDetailsService;
    private final UserMapper userMapper;

    @Override
    protected void doFilterInternal(@NotNull HttpServletRequest request,
                                    @NotNull HttpServletResponse response,
                                    @NotNull FilterChain filterChain) throws ServletException, IOException {
        //白名单
        if (UserContextUtil.isWhiteList(request)) {
            filterChain.doFilter(request, response);
        }
        final String identifier;
        final String jwt = UserContextUtil.extractToken(request);
        identifier = jwtUtil.extractOpenid(jwt);

        if (identifier != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(identifier);

            if (jwtUtil.validateToken(jwt, userDetails)) {
                UsernamePasswordAuthenticationToken authToken =
                    new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authToken);

                // 设置用户上下文
                try {
                    setUserContextFromIdentifier(identifier);
                } catch (Exception e) {
                    log.error("设置用户上下文失败: {}", e.getMessage(), e);
                    // 清理上下文，防止脏数据
                    UserContextHolder.clear();
                }
            }
        }

        try {
            filterChain.doFilter(request, response);
        } finally {
            // 请求完成后清理用户上下文
            UserContextHolder.clear();
        }
    }
    /**
     * 根据标识符设置用户上下文
     */
    private void setUserContextFromIdentifier(String identifier) {
        User user;

        // 判断是用户名还是手机号
        if (identifier.matches("\\d+")) {
            // 纯数字，按手机号查询
            user = userMapper.selectByPhone(identifier);
        } else {
            // 字符串，按用户名查询
            user = userMapper.selectByUsername(identifier);
        }

        if (user != null) {
            // 查询完整用户信息（包括管理员信息）
            User fullUser = userMapper.selectUserWithAdminInfo(user.getId());
            if (fullUser != null) {
                // 创建用户上下文
                UserContext userContext = UserContext.of(
                    fullUser.getId(),
                    fullUser.getUsername(),
                    fullUser.getNickname(),
                    fullUser.getPhone(),
                    fullUser.getAvatarUrl(),
                    fullUser.getUserLevel(),
                    fullUser.getIsAdmin(),
                    fullUser.getAdminRole(),
                    fullUser.getStatus()
                );

                UserContextHolder.setUserContext(userContext);
                log.debug("设置用户上下文成功: userId={}, username={}, isAdmin={}",
                    fullUser.getId(), fullUser.getUsername(), fullUser.getIsAdmin());
            }
        }
    }
}